"""组合指标分析器模块.

实现多个技术指标的组合判断逻辑，支持加权投票和信号融合。
"""

from __future__ import annotations

from typing import Any, Dict, Optional

from .types import SignalDirection, SignalResult, SignalStrength
from .utils import normalize_indicator_name

class CombinedIndicatorAnalyzer:
    """指标组合分析器.
    
    实现多个技术指标的组合判断逻辑，支持加权投票和信号融合。
    """
    
    # 指标权重配置
    INDICATOR_WEIGHTS = {
        # 趋势指标权重
        "macd": 1.0,
        "adx": 1.0,
        "ma_system": 1.0,
        "trend_persistence": 0.8,
        # 动量指标权重
        "rsi": 0.8,
        "kdj": 0.8,
        "cci": 0.8,
        "cmo": 0.7,
        "williams_r": 0.7,
        # 成交量指标权重
        "obv": 0.6,
        "mfi": 0.6,
        # 价格位置指标权重
        "bollinger": 0.7,
        "price_percentile": 0.7,
        "vwap": 0.6,
        # K线形态权重
        "candlestick_patterns": 0.5,
    }
    
    def analyze_trend_system(
        self,
        macd_result: Optional[SignalResult] = None,
        adx_result: Optional[SignalResult] = None,
        ma_result: Optional[SignalResult] = None,
    ) -> SignalResult:
        """分析趋势系统组合.
        
        结合MACD、ADX和均线系统的判断结果。
        
        Parameters
        ----------
        macd_result : Optional[SignalResult], optional
            MACD分析结果
        adx_result : Optional[SignalResult], optional
            ADX分析结果
        ma_result : Optional[SignalResult], optional
            均线系统分析结果
            
        Returns
        -------
        SignalResult
            组合信号分析结果
        """
        results = []
        weights = []
        
        if macd_result and macd_result.direction != SignalDirection.NEUTRAL:
            results.append(macd_result)
            weights.append(self.INDICATOR_WEIGHTS.get("macd", 1.0))
        
        if adx_result and adx_result.direction != SignalDirection.NEUTRAL:
            results.append(adx_result)
            weights.append(self.INDICATOR_WEIGHTS.get("adx", 1.0))
        
        if ma_result and ma_result.direction != SignalDirection.NEUTRAL:
            results.append(ma_result)
            weights.append(self.INDICATOR_WEIGHTS.get("ma_system", 1.0))
        
        if not results:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.0,
                value={"macd": macd_result, "adx": adx_result, "ma": ma_result},
                threshold_info={"reason": "所有指标均为中性"},
            )
        
        # 加权投票
        bullish_score = 0.0
        bearish_score = 0.0
        total_weight = sum(weights)
        
        for result, weight in zip(results, weights):
            if result.direction == SignalDirection.BULLISH:
                bullish_score += weight * result.confidence
            elif result.direction == SignalDirection.BEARISH:
                bearish_score += weight * result.confidence
        
        # 归一化得分
        if total_weight > 0:
            bullish_score /= total_weight
            bearish_score /= total_weight
        
        # 判断方向
        if bullish_score > bearish_score and bullish_score > 0.5:
            confidence = bullish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else SignalStrength.MODERATE
            return SignalResult(
                direction=SignalDirection.BULLISH,
                strength=strength,
                confidence=confidence,
                value={"macd": macd_result, "adx": adx_result, "ma": ma_result},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
        elif bearish_score > bullish_score and bearish_score > 0.5:
            confidence = bearish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else SignalStrength.MODERATE
            return SignalResult(
                direction=SignalDirection.BEARISH,
                strength=strength,
                confidence=confidence,
                value={"macd": macd_result, "adx": adx_result, "ma": ma_result},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
        else:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.2,
                value={"macd": macd_result, "adx": adx_result, "ma": ma_result},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
    
    def analyze_momentum_system(
        self,
        rsi_result: Optional[SignalResult] = None,
        kdj_result: Optional[SignalResult] = None,
        cci_result: Optional[SignalResult] = None,
    ) -> SignalResult:
        """分析动量系统组合.
        
        结合RSI、KDJ和CCI的判断结果。
        
        Parameters
        ----------
        rsi_result : Optional[SignalResult], optional
            RSI分析结果
        kdj_result : Optional[SignalResult], optional
            KDJ分析结果
        cci_result : Optional[SignalResult], optional
            CCI分析结果
            
        Returns
        -------
        SignalResult
            组合信号分析结果
        """
        results = []
        weights = []
        
        if rsi_result and rsi_result.direction != SignalDirection.NEUTRAL:
            results.append(rsi_result)
            weights.append(self.INDICATOR_WEIGHTS.get("rsi", 0.8))
        
        if kdj_result and kdj_result.direction != SignalDirection.NEUTRAL:
            results.append(kdj_result)
            weights.append(self.INDICATOR_WEIGHTS.get("kdj", 0.8))
        
        if cci_result and cci_result.direction != SignalDirection.NEUTRAL:
            results.append(cci_result)
            weights.append(self.INDICATOR_WEIGHTS.get("cci", 0.8))
        
        if not results:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.0,
                value={"rsi": rsi_result, "kdj": kdj_result, "cci": cci_result},
                threshold_info={"reason": "所有指标均为中性"},
            )
        
        # 加权投票（与趋势系统相同逻辑）
        bullish_score = 0.0
        bearish_score = 0.0
        total_weight = sum(weights)
        
        for result, weight in zip(results, weights):
            if result.direction == SignalDirection.BULLISH:
                bullish_score += weight * result.confidence
            elif result.direction == SignalDirection.BEARISH:
                bearish_score += weight * result.confidence
        
        if total_weight > 0:
            bullish_score /= total_weight
            bearish_score /= total_weight
        
        if bullish_score > bearish_score and bullish_score > 0.5:
            confidence = bullish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else SignalStrength.MODERATE
            return SignalResult(
                direction=SignalDirection.BULLISH,
                strength=strength,
                confidence=confidence,
                value={"rsi": rsi_result, "kdj": kdj_result, "cci": cci_result},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
        elif bearish_score > bullish_score and bearish_score > 0.5:
            confidence = bearish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else SignalStrength.MODERATE
            return SignalResult(
                direction=SignalDirection.BEARISH,
                strength=strength,
                confidence=confidence,
                value={"rsi": rsi_result, "kdj": kdj_result, "cci": cci_result},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
        else:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.2,
                value={"rsi": rsi_result, "kdj": kdj_result, "cci": cci_result},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
    
    def analyze_volume_price_system(
        self,
        obv_result: Optional[SignalResult] = None,
        mfi_result: Optional[SignalResult] = None,
        volume_ratio: Optional[float] = None,
    ) -> SignalResult:
        """分析量价系统组合.
        
        结合OBV、MFI和成交量比率的判断结果。
        
        Parameters
        ----------
        obv_result : Optional[SignalResult], optional
            OBV分析结果
        mfi_result : Optional[SignalResult], optional
            MFI分析结果
        volume_ratio : Optional[float], optional
            成交量比率（volume / volume_ma）
            
        Returns
        -------
        SignalResult
            组合信号分析结果
        """
        results = []
        weights = []
        
        if obv_result and obv_result.direction != SignalDirection.NEUTRAL:
            results.append(obv_result)
            weights.append(self.INDICATOR_WEIGHTS.get("obv", 0.6))
        
        if mfi_result and mfi_result.direction != SignalDirection.NEUTRAL:
            results.append(mfi_result)
            weights.append(self.INDICATOR_WEIGHTS.get("mfi", 0.6))
        
        # 成交量比率判断（简单规则：volume_ratio > 1.2 看多，< 0.8 看空）
        if volume_ratio is not None and not pd.isna(volume_ratio):
            if volume_ratio > 1.2:
                volume_result = SignalResult(
                    direction=SignalDirection.BULLISH,
                    strength=SignalStrength.MODERATE,
                    confidence=0.6,
                    value=volume_ratio,
                    threshold_info={"threshold": 1.2},
                )
                results.append(volume_result)
                weights.append(0.5)
            elif volume_ratio < 0.8:
                volume_result = SignalResult(
                    direction=SignalDirection.BEARISH,
                    strength=SignalStrength.MODERATE,
                    confidence=0.6,
                    value=volume_ratio,
                    threshold_info={"threshold": 0.8},
                )
                results.append(volume_result)
                weights.append(0.5)
        
        if not results:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.0,
                value={"obv": obv_result, "mfi": mfi_result, "volume_ratio": volume_ratio},
                threshold_info={"reason": "所有指标均为中性"},
            )
        
        # 加权投票
        bullish_score = 0.0
        bearish_score = 0.0
        total_weight = sum(weights)
        
        for result, weight in zip(results, weights):
            if result.direction == SignalDirection.BULLISH:
                bullish_score += weight * result.confidence
            elif result.direction == SignalDirection.BEARISH:
                bearish_score += weight * result.confidence
        
        if total_weight > 0:
            bullish_score /= total_weight
            bearish_score /= total_weight
        
        if bullish_score > bearish_score and bullish_score > 0.5:
            confidence = bullish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else SignalStrength.MODERATE
            return SignalResult(
                direction=SignalDirection.BULLISH,
                strength=strength,
                confidence=confidence,
                value={"obv": obv_result, "mfi": mfi_result, "volume_ratio": volume_ratio},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
        elif bearish_score > bullish_score and bearish_score > 0.5:
            confidence = bearish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else SignalStrength.MODERATE
            return SignalResult(
                direction=SignalDirection.BEARISH,
                strength=strength,
                confidence=confidence,
                value={"obv": obv_result, "mfi": mfi_result, "volume_ratio": volume_ratio},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
        else:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.2,
                value={"obv": obv_result, "mfi": mfi_result, "volume_ratio": volume_ratio},
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score},
            )
    
    def analyze_comprehensive_system(self, all_results: Dict[str, SignalResult]) -> SignalResult:
        """分析综合系统（所有指标投票）.
        
        对所有技术指标进行加权投票，得出综合判断。
        
        Parameters
        ----------
        all_results : Dict[str, SignalResult]
            所有指标的分析结果字典
            
        Returns
        -------
        SignalResult
            综合信号分析结果
        """
        results = []
        weights = []
        
        for indicator_name, result in all_results.items():
            if result and result.direction != SignalDirection.NEUTRAL:
                normalized_name = normalize_indicator_name(indicator_name)
                weight = self.INDICATOR_WEIGHTS.get(normalized_name, 0.5)
                results.append(result)
                weights.append(weight)
        
        if not results:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.0,
                value=all_results,
                threshold_info={"reason": "所有指标均为中性"},
            )
        
        # 加权投票
        bullish_score = 0.0
        bearish_score = 0.0
        total_weight = sum(weights)
        
        for result, weight in zip(results, weights):
            if result.direction == SignalDirection.BULLISH:
                bullish_score += weight * result.confidence
            elif result.direction == SignalDirection.BEARISH:
                bearish_score += weight * result.confidence
        
        if total_weight > 0:
            bullish_score /= total_weight
            bearish_score /= total_weight
        
        if bullish_score > bearish_score and bullish_score > 0.4:
            confidence = bullish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else (SignalStrength.MODERATE if confidence > 0.5 else SignalStrength.WEAK)
            return SignalResult(
                direction=SignalDirection.BULLISH,
                strength=strength,
                confidence=confidence,
                value=all_results,
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score, "total_indicators": len(results)},
            )
        elif bearish_score > bullish_score and bearish_score > 0.4:
            confidence = bearish_score
            strength = SignalStrength.STRONG if confidence > 0.7 else (SignalStrength.MODERATE if confidence > 0.5 else SignalStrength.WEAK)
            return SignalResult(
                direction=SignalDirection.BEARISH,
                strength=strength,
                confidence=confidence,
                value=all_results,
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score, "total_indicators": len(results)},
            )
        else:
            return SignalResult(
                direction=SignalDirection.NEUTRAL,
                strength=SignalStrength.WEAK,
                confidence=0.2,
                value=all_results,
                threshold_info={"bullish_score": bullish_score, "bearish_score": bearish_score, "total_indicators": len(results)},
            )


def extract_indicator_values(features: pd.DataFrame, latest_only: bool = True) -> Dict[str, Any]:
    """从特征DataFrame中提取指标值.
    
    Parameters
    ----------
    features : pd.DataFrame
        特征DataFrame
    latest_only : bool, default True
        是否只提取最新一行的值
        
    Returns
    -------
    Dict[str, Any]
        指标值字典，key为指标名称，value为指标值
    """
    if latest_only:
        # 只提取最新一行
        row = features.iloc[-1]
    else:
        # 提取所有行（返回字典的字典）
        return {idx: extract_indicator_values(features.loc[[idx]], latest_only=True) for idx in features.index}
    
    values = {}
    
    # 提取各个指标值
    for col in features.columns:
        if pd.notna(row[col]):
            values[col] = row[col]
    
    return values

